package main

import (
	"center/admin"
	"center/contact"
	"center/db"
	"center/endpoint"
	"center/migration"
	"center/repair"
	"common/cfgstruct"
	db2 "common/db"
	"common/kms"
	"common/log"
	"common/process"
	"common/run"
	"context"
	"encoding/json"
	"fmt"
	"github.com/spf13/cobra"
	"github.com/wuzfei/go-helper/path"
	"os"
	"path/filepath"
)

type Config struct {
	DB       db.Config
	Admin    admin.Config
	Endpoint endpoint.Config
	Contact  contact.Config
	Log      log.Config
	KMS      kms.Config
	Repair   repair.Config
}

var (
	configFile string
	rootCmd    = &cobra.Command{
		Use:   "ecenter",
		Short: "分布式存储-卫星服务",
	}
	runCmd = &cobra.Command{
		Use:   "run",
		Short: "运行",
		RunE:  cmdRun,
	}
	gcCmd = &cobra.Command{
		Use:   "gc",
		Short: "删除过期文件清理",
		RunE:  cmdGc,
	}
	setupCmd = &cobra.Command{
		Use:         "setup",
		Short:       "初始化配置文件",
		RunE:        cmdSetup,
		Annotations: map[string]string{"type": "setup"},
	}
	migrationCmd = &cobra.Command{
		Use:   "migration",
		Short: "数据库迁移命令",
		RunE:  cmdMigration,
	}
	configCmd = &cobra.Command{
		Use:   "config",
		Short: "查看当前所有配置",
		RunE:  cmdConfig,
	}
	runConfig   Config
	setupConfig Config
)

func main() {

	defaultConfig := path.ApplicationDir("ecenter", process.DefaultCfgFilename)
	cfgstruct.SetupFlag(rootCmd, &configFile, "config", defaultConfig, "配置文件")
	//根据环境读取默认配置
	defaults := cfgstruct.DefaultsFlag(rootCmd)
	currentDir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
	//程序目录
	rootDir := cfgstruct.ConfigVar("ROOT", currentDir)
	//设置系统的HOME变量
	envHome := cfgstruct.ConfigVar("HOME", os.Getenv("HOME"))
	rootCmd.AddCommand(runCmd)
	rootCmd.AddCommand(setupCmd)
	rootCmd.AddCommand(migrationCmd)
	rootCmd.AddCommand(configCmd)
	process.Bind(runCmd, &runConfig, defaults, cfgstruct.ConfigFile(configFile), envHome, rootDir)
	process.Bind(gcCmd, &runConfig, defaults, cfgstruct.ConfigFile(configFile), envHome, rootDir)
	process.Bind(migrationCmd, &runConfig, defaults, cfgstruct.ConfigFile(configFile), envHome, rootDir)
	process.Bind(configCmd, &runConfig, defaults, cfgstruct.ConfigFile(configFile), envHome, rootDir)
	process.Bind(setupCmd, &setupConfig, defaults, cfgstruct.ConfigFile(configFile), envHome, cfgstruct.SetupMode(), rootDir)
	process.Exec(rootCmd)
}

func cmdRun(cmd *cobra.Command, args []string) error {
	ctx, _ := process.Ctx(cmd)
	log2 := log.NewZapLog(&runConfig.Log)
	centerDb, err := db.NewDBLayer(runConfig.DB.Database, log2.Named("db"), runConfig.DB.LogLevel)

	if err != nil {
		panic(err)
	}
	rGroup := run.NewGroup()
	//ws服务
	contactNode := contact.NewContactServer(log2.Named("contact"), runConfig.Contact, contact.NewEndpoint(centerDb, log2.Named("Endpoint")), centerDb)
	rGroup.Add(contactNode)
	//nodeClient := contactNode.NodeClient()
	//fmt.Println("下面依赖nodeClient的服务需要向节点发送消息的可以传这个进去使用", nodeClient)
	//admin api服务
	rGroup.Add(admin.NewServer(log2.Named("admin"), centerDb, runConfig.Admin, kms.NewClient(&runConfig.KMS)))
	//drpc服务
	rGroup.Add(endpoint.NewMetainfoServer(log2.Named("metainfo"), centerDb, runConfig.Endpoint, contactNode))
	//repair
	rGroup.Add(repair.NewService(log2, centerDb, runConfig.Repair))
	return rGroup.Run(ctx)
}

func cmdSetup(cmd *cobra.Command, args []string) error {
	return process.SaveConfig(cmd, configFile)
}

func cmdGc(cmd *cobra.Command, args []string) error {
	return process.SaveConfig(cmd, configFile)
}

func cmdMigration(cmd *cobra.Command, args []string) error {
	gormDb, err := db2.NewGormDB(runConfig.DB.Database)
	if err != nil {
		return err
	}
	m := migration.NewMigration(gormDb)
	return m.UpdateTables(context.Background())
}

func cmdConfig(cmd *cobra.Command, args []string) error {
	fmt.Printf("当前运行环境：[%s]\n", cfgstruct.DefaultsType())
	fmt.Println("当前配置文件路径：", configFile)
	output, _ := json.MarshalIndent(runConfig, "", " ")
	fmt.Println(string(output))
	return nil
}
